package com.firmboy.zoo;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.util.Collections;
import java.util.List;

/**
 * zookeeper实现分布式锁
 *
 * @author firmboy
 * @create 2018-05-03 上午10:04
 **/
public class ZooLock {

    private static String rootPath = "/zookLock";

    private String lockName = "";

    private volatile static ZooLock zooLock;

    private static ZooKeeper zk = null;

    private ZooLock(String lockName){
        this.lockName = lockName;
    }

    public static ZooLock getInstance(String lockName){
        if(zooLock==null){
            synchronized (ZooLock.class){
                if(zooLock==null){
                    zooLock = new ZooLock(lockName);
                }
            }
        }
        return zooLock;
    }

    static {
        try {
            zk = new ZooKeeper("tcp.ittun.com:47203", 2000, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    //System.out.println("已经出发了" + watchedEvent.getType() + "事件！");
                }
            });
            Stat exists = zk.exists(rootPath, false);
            if (exists==null){
                zk.create(rootPath,"rootPath".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }




    /**
     * 获取分布式锁
     */
    public String getLock(){
        String lockPath = null;
        if(zk==null){
            throw new RuntimeException("zk init error");
        }
        try {
            //创建一个节点，这个节点是自带顺序的
            lockPath = zk.create(rootPath + "/" + lockName, Thread.currentThread().getName().getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
            System.out.println("当前创建的路径返回的s："+lockPath);
            String s = lockPath.substring(lockPath.lastIndexOf("/")+1,lockPath.length());
            System.out.println("整理后的路径："+s);
            //获取这个路径下面的所有节点，看看我们创建的节点是不是最小节点

            while(true){
                List<String> children = ZooLock.zk.getChildren(rootPath, false);
                Collections.sort(children);
                for (String str:children
                        ) {
                    System.out.println("孩子路径："+str);
                }
                int index = children.indexOf(s);
                if(index==0){
                    System.out.println("获取锁成功");
                    break;
                }else{
                    String preLockPath = children.get(index-1);
                    Watcher watcher = new Watcher() {
                        @Override
                        public void process(WatchedEvent event) {
                            System.out.println("程序被唤醒了");
                            synchronized (this) {
                                notifyAll();
                            }
                        }
                    };
                    zk.exists(rootPath+"/"+preLockPath, watcher);
                    System.out.println("进入休眠");
                    synchronized (watcher){
                        watcher.wait();
                    }
                }
            }
            System.out.println("程序继续向下执行");
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            return lockPath;
        }
    }


    public void releaseLock(String lockPath){
        try {
            zk.delete(lockPath,-1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }
}
